﻿using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

using Pibby.Core.IO;

namespace Pibby.Controls
{
	/// <summary>
	/// Shows how close we are to using all the space up in a 
	/// portable media device in the form of a progress bar.
	/// </summary>
	public partial class PlayerCapacityView : UserControl
	{
		#region Variables

		private Color _safeColour;
		private Color _warningColour;
		private Color _dangerColour;

		private bool _drawThresholds = true;

		private DiskSpaceInfo _diskUse = new DiskSpaceInfo();

		#endregion

		#region Properties

		public long Value
		{
			get { return this._diskUse.Value; }
			set { this._diskUse.Value = value; }
		}

		public long FreeSpace
		{
			get { return this._diskUse.FreeSpace; }
			set { this._diskUse.FreeSpace = value; }
		}

		public long Maximum
		{
			get { return this._diskUse.Maximum; }
			set { this._diskUse.Maximum = value; }
		}

		public bool DrawThresholds
		{
			get { return _drawThresholds; } 
			set 
			{ 
				_drawThresholds = value; 
				this.Invalidate();
			}
		}

		public Color SafeColour
		{
			get { return _safeColour; } 
			set
			{
				_safeColour = value;
				this.Invalidate();
			}
		}

		public Color WarningColour
		{
			get { return _warningColour; } 
			set
			{
				_warningColour = value;
				this.Invalidate();
			}
		}

		public Color DangerColour
		{
			get { return _dangerColour; } 
			set
			{
				_dangerColour = value;
				this.Invalidate();
			}
		}

		#endregion Properties

		#region Constructors

		public PlayerCapacityView()
		{
			this.SafeColour = Color.FromArgb (143, 212, 76);
			this.WarningColour = Color.FromArgb(242, 151, 62);
			this.DangerColour = Color.Red;

			this.DrawThresholds = true;

			InitializeComponent();

			this.SafeColour = Color.FromArgb(143, 212, 76);
			this.WarningColour = Color.FromArgb(242, 151, 62);
			this.DangerColour = Color.Red;

			this.SetStyle(ControlStyles.DoubleBuffer, true);
			this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			this.SetStyle(ControlStyles.ResizeRedraw, true);
			this.SetStyle(ControlStyles.UserPaint, true);
			this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
			this.BackColor = Color.Transparent;
		}

		#endregion Constructors

		public void SetDrive(IDrive drive)
		{
			this._diskUse = new DiskSpaceInfo(drive);
		}

		public void SetDrive(long availableSpace, long totalSize)
		{
			this._diskUse = new DiskSpaceInfo(availableSpace, totalSize);
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			Rectangle safeRectangle = new Rectangle(this.ClientRectangle.Left, 
										this.ClientRectangle.Top, 
										CalculatePositionFromPercent (this.ClientRectangle.Width, this._diskUse.SafeRegionAsPercent),
										this.ClientRectangle.Height);

			Rectangle warningRectangle = new Rectangle(safeRectangle.Right,
										this.ClientRectangle.Top,
										CalculatePositionFromPercent(this.ClientRectangle.Width, this._diskUse.WarningRegionAsPercent),
										this.ClientRectangle.Height);

			Rectangle dangerRectangle = new Rectangle(warningRectangle.Right,
										this.ClientRectangle.Top,
										CalculatePositionFromPercent(this.ClientRectangle.Width, this._diskUse.DangerRegionAsPercent),
										this.ClientRectangle.Height);

			this.DrawSafeContent(e.Graphics, safeRectangle);
			this.DrawWarningContentIfRequired(e.Graphics, warningRectangle);
			this.DrawDangerContentIfRequired(e.Graphics, dangerRectangle);

			this.DrawOverlay(e.Graphics, this.ClientRectangle, safeRectangle.Right, warningRectangle.Right);
		}

		private void DrawSafeContent(Graphics g, Rectangle safeRectangle)
		{
			HslColor darkerColour = new HslColor (this.SafeColour).Darken (0.25);

			using (Brush brush = new LinearGradientBrush(safeRectangle, this.SafeColour, darkerColour.ToColor (), LinearGradientMode.Vertical))
			{
				int position = this.CalculatePositionFromPercent(safeRectangle.Width,
																(int)((this.Value * 100) / this._diskUse.WarningThreshold));

				g.FillRectangle(brush,
								safeRectangle.Left, 
								safeRectangle.Top, 
								position, 
								safeRectangle.Height);
			}
		}

		private void DrawWarningContentIfRequired(Graphics g, Rectangle warningRectangle)
		{
			if (this._diskUse.Status != DiskSpaceStatus.Normal)
			{
				HslColor darkerColour = new HslColor(this.WarningColour).Darken(0.25);

				using (Brush brush = new LinearGradientBrush(warningRectangle, this.WarningColour, darkerColour.ToColor(), LinearGradientMode.Vertical))
				{
					int warningPC = (int)(((this.Value - this._diskUse.WarningThreshold) * 100) / (this._diskUse.DangerThreshold - this._diskUse.WarningThreshold));
					
					int position = this.CalculatePositionFromPercent(warningRectangle.Width, warningPC);

					g.FillRectangle(brush,
									warningRectangle.Left,
									warningRectangle.Top,
									position,
									warningRectangle.Height);
				}
			}
		}

		private void DrawDangerContentIfRequired(Graphics g, Rectangle dangerRectangle)
		{
			if (this._diskUse.Status == DiskSpaceStatus.Danger || this._diskUse.Status == DiskSpaceStatus.Full)
			{
				HslColor darkerColour = new HslColor(this.DangerColour).Darken(0.25);

				using (Brush brush = new LinearGradientBrush(dangerRectangle, this.DangerColour, darkerColour.ToColor(), LinearGradientMode.Vertical))
				{
					int dangerPC = (int)(((this.Value - this._diskUse.DangerThreshold) * 100) / (this.Maximum - this._diskUse.DangerThreshold));

					int position = this.CalculatePositionFromPercent(dangerRectangle.Width, dangerPC);

					g.FillRectangle(brush,
									dangerRectangle.Left,
									dangerRectangle.Top,
									position,
									dangerRectangle.Height);
				}
			}
		}

		private void DrawOverlay(Graphics g, Rectangle clientRectangle, int warningPosition, int dangerPosition)
		{
			using (Pen overlayPen = new Pen(this.SafeColour))
			{
				g.DrawRectangle(overlayPen, clientRectangle.Left, clientRectangle.Top,
					clientRectangle.Width - 1, clientRectangle.Height - 1);
			}

			if (this.DrawThresholds)
			{
				using (Pen overlayPen = new Pen(this.WarningColour))
				{
					g.DrawRectangle(overlayPen, warningPosition, clientRectangle.Top,
									dangerPosition - warningPosition - 1, clientRectangle.Height - 1);
				}

				using (Pen overlayPen = new Pen (this.DangerColour))
				{
					g.DrawRectangle(overlayPen, dangerPosition, clientRectangle.Top,
									clientRectangle.Width - dangerPosition - 1, clientRectangle.Height - 1);
				}
			}
		}

		private int CalculatePositionFromPercent(int clientWidth, int percent)
		{
			if (percent > 100)
				percent = 100;

			return (clientWidth * percent) / 100;
		}
	}
}
